﻿@page "/Managers"
@using HardHatCore.ApiModels.Requests
@using HardHatCore.ApiModels.Responses
@using HardHatCore.ApiModels.Shared;
@using HardHatCore.HardHatC2Client.Components;
@using HardHatCore.HardHatC2Client.Services;
@using Models
@using RestSharp
@using System.Text.RegularExpressions
@using RestSharp.Authenticators
@using Blazored.LocalStorage
@using MudExtensions.Enums
@using System.Reflection;
@using HardHatCore.HardHatC2Client.Utilities;
@inject RestClient _restClient
@inject IToastService toastService
@inject ISnackbar Snackbar
@inject NavigationManager NavigationManager


<CascadingAuthenticationState>
    <AuthorizeView Roles="Operator,TeamLead">
        <Authorized>
            <!-- top half of page being a table of the current managers in the managersList with headers such as Name, type, ConnectionAddress, ConnectionPort, CreationTime, Active -->
            <br>
            <h3>Managers</h3>
            <br>

            <MudTable Items="@managersList" Virtualize="true" HorizontalScrollbar="true" FixedHeader="true" Height="30vh" Hover="true" Dense="true" Outlined="true" Striped="true">
                <HeaderContent>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Name</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Type</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Connection Address</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Connection Port</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Bind Address</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Bind Port</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Created Time</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Active</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">C2 Profile</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Options</MudTh>
                </HeaderContent>
                <RowTemplate Context="rowContext">
                    <MudTd>@rowContext.Name</MudTd>
                    <MudTd>@rowContext.Type @displayConnectionMode(rowContext)</MudTd>
                    <MudTd>@rowContext.ConnectionAddress</MudTd>
                    <MudTd>@rowContext.ConnectionPort</MudTd>
                    <MudTd>@rowContext.BindAddress</MudTd>
                    <MudTd>@rowContext.BindPort</MudTd>
                    <MudTd>@rowContext.CreationTime</MudTd>
                    <MudTd>@rowContext.Active</MudTd>
                    <MudTd>
                        <MudIconButton OnClick="() => OnC2ProfileButtonClicked(rowContext.C2profile)" Icon="@Icons.Material.Filled.Visibility" Color="@Color.Primary" aria-label="view C2 Profile Info" />
                        <MudMessageBox @ref="C2mbox" Title="C2 Profile Info" CancelText="Close">
                            <MessageContent>
                                @if (true)
                                {
                                    //create a new profile object and set it to the profile object of the rowContext
                                    var profile = rowContext.C2profile;
                                    //for each item in the profile objects properties add a line that is the property name and the value of the property
                                    foreach (PropertyInfo prop in profile.GetType().GetProperties())
                                    {
                                        var value = prop.GetValue(profile, null);
                                        if (value == null) continue; // Skip if the value is null

                                        if (prop.PropertyType == typeof(List<string>))
                                        {
                                            var list = (List<string>)value;
                                            foreach (var item in list)
                                            {
                                                <p>@prop.Name : @item</p>
                                            }
                                        }
                                        else if (value is string stringValue)
                                        {
                                            // Skip if the string value is the full type name of any property
                                            if (profile.GetType().GetProperties().Any(p => p.PropertyType.FullName == stringValue)) continue;

                                            <p>@prop.Name : @stringValue</p>
                                        }
                                        else
                                        {
                                            <p>@prop.Name : @value</p>
                                        }
                                    }
                                }
                            </MessageContent>
                        </MudMessageBox>
                    </MudTd>
                    <MudTd>
                        <MudButtonGroup Color="Color.Primary" Variant="Variant.Outlined">
                            <MudMenu Icon="@Icons.Material.Filled.ArrowDropDown">
                                <MudMenuItem OnClick="() =>ContextMenuItems(0,rowContext)">Remove</MudMenuItem>
                                <MudMenuItem OnClick="() =>ContextMenuItems(1,rowContext)">Edit</MudMenuItem>
                            </MudMenu>
                        </MudButtonGroup>
                    </MudTd>
                </RowTemplate>
                <PagerContent>
                    <MudTablePager HorizontalAlignment="HorizontalAlignment.End" />
                </PagerContent>
            </MudTable>
            <!-- bottom half of page being a form to add a new Manager -->
            <br>
            <br>
            <div class ="container-fluid">
                <h3>Create New Managers</h3>
                <br>

                @if(formSubmitManager.Type == ManagerType.smb)
                {
                    IsSmbSelected = true;
                    IsHttpSelected = false;
                    IsTcpSelected = false;
                }
                else if (formSubmitManager.Type == ManagerType.tcp)
                {
                    IsSmbSelected = false;
                    IsHttpSelected = false;
                    IsTcpSelected = true;
                }
                else
                {
                    IsSmbSelected = false;
                    IsHttpSelected = true;
                    IsTcpSelected = false;
                }
                
                    <MudStepper @ref="_stepper" Class="mud-width-full" HeaderSize="Size.Large" Color="Color.Primary" Variant="Variant.Filled" HeaderTextView="MudExtensions.Enums.HeaderTextView.All" PreventStepChangeAsync="new Func<StepChangeDirection, Task<bool>>(CheckChange)"  >
                    <ChildContent>
                        <MudStep Icon="@Icons.Material.Filled.Headphones" Title="Name & type">
                            <ChildContent>
                                <MudForm @ref="_form" @bind-IsValid="@success">
                                <MudTextField @ref="managerNameFormEntry" Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Name" Required="true" @bind-value="formSubmitManager.Name" RequiredError="manager name is required!" />
                                <MudSelectExtended @ref="managerTypeFormSelect" Class="mb-4" T="ManagerType" Variant="Variant.Filled" Clearable="true" Label="Manager Type" Required="true" @bind-value="formSubmitManager.Type" RequiredError="Type is required!">
                                    <MudSelectItemExtended Value="@(ManagerType.http)" />
                                    <MudSelectItemExtended Value="@(ManagerType.https)" />
                                    <MudSelectItemExtended Value="@(ManagerType.tcp)" />
                                    <MudSelectItemExtended Value="@(ManagerType.smb)" />
                                </MudSelectExtended>
                                </MudForm>
                            </ChildContent>
                        </MudStep>          
                        <MudStep Icon="@MaterialDesignIcons.Normal.Plus" Title="Advanced Info">
                            <ChildContent>
                                <MudForm @ref="_form2">
                            @if (formSubmitManager.Type == ManagerType.http && !String.IsNullOrEmpty(formSubmitManager.Name) || formSubmitManager.Type == ManagerType.https && !String.IsNullOrEmpty(formSubmitManager.Name))
                            {
                                <MudTextField Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Connection Address" Required=@IsHttpSelected @bind-value="formSubmitManager.ConnectionAddress" RequiredError="callback address is required!" />
                                <MudTextField Class="mb-4 mt-4" T="int?"  Variant="Variant.Filled" Clearable="true" Label="Connection Port" Required=@IsHttpSelected @bind-value="formSubmitManager.ConnectionPort" RequiredError="port is required!" />
                                        @*<MudTextField Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Bind Address" Required=@IsHttpSelected @bind-value="formSubmitManager.BindAddress" RequiredError="bind address is required!" />*@
    
                                <MudComboBox T=string Required=@IsHttpSelected @bind-value="formSubmitManager.BindAddress" RequiredError="bind address is required!" Variant="Variant.Filled" Label="Bind Address" MultiSelection="false" Editable="true"
                                                ShowCheckbox="true" Bordered="true" Dense="Dense.Slim" Color="@Color.Primary" Clearable="true">
                                    <ChildContent>
                                        @foreach (string item in bindableIpAddresses)
                                        {
                                            <MudComboBoxItem Value="@item" Text="@item"></MudComboBoxItem>
                                        }
                                    </ChildContent>
                                    <PopoverEndContent>
                                        <div class="d-flex gap-4 pa-4">
                                            <MudIconButton Icon="@Icons.Material.Filled.Add" Variant="Variant.Outlined" Color="@Color.Primary" OnClick="(()=>bindableIpAddresses.Add(_bindAddressToAdd))" />
                                            <MudTextFieldExtended @bind-Value="_bindAddressToAdd" Variant="Variant.Outlined" Margin="Margin.Dense" />
                                        </div>
                                    </PopoverEndContent>
                                </MudComboBox>
                                <MudTextField Class="mb-4 mt-4" T="int?"  Variant="Variant.Filled" Clearable="true" Label="Bind Port" Required=@IsHttpSelected @bind-value="formSubmitManager.BindPort" RequiredError="bind port is required!" />
                                <div class="d-flex align-center justify-space-between">
                                    <MudSelectExtended ValuePresenter="ValuePresenter.ItemContent" Class="mb-4" T="C2Profile" Variant="Variant.Filled" Clearable="true" Label="C2 Profile" Required="true" @bind-value="formSubmitManager.C2profile" RequiredError="C2 Profile required!">
                                        @foreach(C2Profile profile in C2profiles)
                                        {
                                            <MudSelectItemExtended Value="@(profile)">@profile.Name</MudSelectItemExtended>
                                        }
                                    </MudSelectExtended>
                                    <MudIconButton Icon="@Icons.Material.Filled.Edit" @onclick="@((e) => OpenEditDialog(formSubmitManager.C2profile))" Variant="Variant.Filled" Color="Color.Primary"></MudIconButton>
                                    <MudIconButton Icon="@Icons.Material.Filled.Add" @onclick="OpenCreateDialog" Variant="Variant.Filled" Color="Color.Primary"></MudIconButton>
                                </div>
                            }
                            else if(formSubmitManager.Type == ManagerType.tcp && !String.IsNullOrEmpty(formSubmitManager.Name))
                            {
                                bool IsBind = false;
                                bool IsReverse = false;
                                if (formSubmitManager.connectionMode == ConnectionMode.bind)
                                {
                                    IsBind = true;
                                    IsReverse = false;
                                }
                                else if (formSubmitManager.connectionMode == ConnectionMode.reverse)
                                {
                                    IsBind = false;
                                    IsReverse = true;
                                }
                                <MudTextField Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Connection Address" Required=@IsReverse Disabled=@IsBind @bind-value="formSubmitManager.ConnectionAddress" RequiredError="callback address is required!" />
                                <MudTextField Class="mb-4 mt-4" T="int?" Variant="Variant.Filled" Clearable="true" Label="Connect Port" Required=@IsReverse Disabled=@IsBind @bind-value="formSubmitManager.BindPort" RequiredError="bind port is required!" />
                                <MudTextField Class="mb-4 mt-4" T="int?" Variant="Variant.Filled" Clearable="true" Label="Listen Port" Required=@IsBind Disabled=@IsReverse @bind-value="formSubmitManager.ListenPort" RequiredError="listen port is required!" />
                                <MudTextField Class="mb-4 mt-4" T="bool?" Variant="Variant.Filled" Clearable="true" Label="Listen on Local host only?" Required=@IsBind Disabled=@IsReverse @bind-value="formSubmitManager.IsLocalHost" RequiredError="is localhost only required!" />
                                <MudSelectExtended Class="mb-4" T="ConnectionMode" Variant="Variant.Filled" Clearable="true" Label="Connection Direction" Required=@IsTcpSelected @bind-value="formSubmitManager.connectionMode" RequiredError="connection mode is required!">
                                    <MudSelectItemExtended Value="@(ConnectionMode.bind)" />
                                    <MudSelectItemExtended Value="@(ConnectionMode.reverse)" />
                                </MudSelectExtended>

                            }
                            else if(formSubmitManager.Type == ManagerType.smb)
                            {
                                bool IsBind = false;
                                bool IsReverse = false;
                                if (formSubmitManager.connectionMode == ConnectionMode.bind)
                                {
                                    IsBind = true;
                                    IsReverse = false;
                                }
                                else if (formSubmitManager.connectionMode == ConnectionMode.reverse)
                                {
                                    IsBind = false;
                                    IsReverse = true;
                                }
                                <MudTextField Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Named Pipe" Required=@IsSmbSelected @bind-value="formSubmitManager.NamedPipe" RequiredError="namedpipe is required!" />
                                <MudTextField Class="mb-4 mt-4" T="string" Variant="Variant.Filled" Clearable="true" Label="Connection Address" Required=@IsReverse Disabled=@IsBind @bind-value="formSubmitManager.ConnectionAddress" RequiredError="callback address is required!" />
                                <MudSelectExtended Class="mb-4" T="ConnectionMode" Variant="Variant.Filled" Clearable="true" Label="Connection Direction" Required=@IsSmbSelected @bind-value="formSubmitManager.connectionMode" RequiredError="connection mode is required!">
                                    <MudSelectItemExtended Value="@(ConnectionMode.bind)" />
                                    <MudSelectItemExtended Value="@(ConnectionMode.reverse)" />
                                </MudSelectExtended>
                            }
                        </MudForm>
                        </ChildContent>
                        </MudStep>
                    </ChildContent>
                    <ActionContent>
                        @if (_stepper.IsAllStepsCompleted() && success)
                        {
                            handleValidSubmit();
                            _stepper.Reset();
                            managerNameFormEntry.Clear();
                            managerTypeFormSelect.Clear();
                            _form.Reset();
                            _form2.Reset();
                            StateHasChanged();
                        }
                        <MudSpacer/>
                    </ActionContent>
                    </MudStepper>                                     
            </div>
        </Authorized>
    </AuthorizeView>
    <AuthorizeView Roles="Guest">
        <Authorized>
                                    
            <!-- top half of page being a table of the current managers in the managersList with headers such as Name, type, ConnectionAddress, ConnectionPort, CreationTime, Active -->
            <h3 class="text-center">Managers</h3>
            <br>
                            
            <MudTable Items="@managersList" Virtualize="true" HorizontalScrollbar="true" FixedHeader="true" Height="30vh" Hover="true" Dense="true" Outlined="true" Striped="true">
                <HeaderContent>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Name</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Type</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Connection Address</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Connection Port</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Created Time</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Active</MudTh>
                    <MudTh Style="@setStyle(Settings.IsCheckedBox)">Options</MudTh>
                </HeaderContent>
                <RowTemplate Context="rowContext">
                    <MudTd>@rowContext.Name</MudTd>
                    <MudTd>@rowContext.Type @displayConnectionMode(rowContext)</MudTd>
                    <MudTd>@rowContext.ConnectionAddress</MudTd>
                    <MudTd>@rowContext.ConnectionPort</MudTd>
                    <MudTd>@rowContext.CreationTime</MudTd>
                    <MudTd>@rowContext.Active</MudTd>
                    <MudTd>
                        <MudButtonGroup Color="Color.Primary" Variant="Variant.Outlined">
                            <MudMenu Disabled="true"  Icon="@Icons.Material.Filled.ArrowDropDown">
                                <MudMenuItem OnClick="() =>ContextMenuItems(0,rowContext)">Remove</MudMenuItem>
                                <MudMenuItem OnClick="() =>ContextMenuItems(1,rowContext)">Edit</MudMenuItem>
                            </MudMenu>
                        </MudButtonGroup>
                    </MudTd>
                </RowTemplate>
                <PagerContent>
                    <MudTablePager HorizontalAlignment="HorizontalAlignment.End" />
                </PagerContent>
            </MudTable>
        </Authorized>
    </AuthorizeView>
    <AuthorizeView Roles="TeamLead,Operator,Guest,Administrator">
               <NotAuthorized>
                    <h1 class="text-center">Not Authorized</h1>
                    <UnAuthorizedDialogBox></UnAuthorizedDialogBox>
                </NotAuthorized>
    </AuthorizeView>
</CascadingAuthenticationState>



@code {
    private Manager formSubmitManager = new Manager();
    public static List<Manager> managersList = new List<Manager>();
    private static ToastService _toastService;
    private bool success;
    private string[] errors = { };
    private bool IsHttpSelected = false;
    private bool IsSmbSelected = false;
    private bool IsTcpSelected = false;
    public static List<C2Profile> C2profiles = new();
    public static List<string> bindableIpAddresses = new() { "127.0.0.1" };
    MudStepper _stepper;
    MudForm _form;
    MudTextField<string> managerNameFormEntry;
    MudSelectExtended<ManagerType>? managerTypeFormSelect;
    MudForm _form2;
    bool _loading;
    MudMessageBox C2mbox;
    string _bindAddressToAdd = "";

    [Inject] 
    private IDialogService DialogService { get; set; }
    [Inject]
    public ILocalStorageService LocalStorage { get; set; }

    private static Timer timer = null;

    string state = "Message box hasn't been opened yet";

    private string setStyle(bool IsDark)
    {
        if(IsDark)
        {
            return "background:white; color:black;";
        }
        return "background:#333333; color:white;"; 
    }
    private string setTabStyle(bool IsDark)
    {
        if (IsDark)
        {
            return "background:#32333d; color:white;";
        }
        return "background:white; color:black;";
    }

    private async void OnC2ProfileButtonClicked(C2Profile profile)
    {
        bool? result = await C2mbox.Show();
        state = result == null ? "Closed" : "Ok";
        StateHasChanged();
    }

    public async Task handleValidSubmit()
    {
        if (formSubmitManager.Type == ManagerType.http)
        {
            await CreateHttpManager();

        }
        else if (formSubmitManager.Type == ManagerType.https)
        {
            await CreateHttpsManager();
        }
        else if(formSubmitManager.Type == ManagerType.smb)
        {
            await CreateSMBManager();
        }
        else if (formSubmitManager.Type == ManagerType.tcp)
        {
            await CreateTCPManager();
        }
        formSubmitManager= new Manager();
    }

    private async Task<bool> CheckChange(StepChangeDirection direction)
    {
        // Always allow stepping backwards, even if forms are invalid
        if (direction == StepChangeDirection.Backward)
        {
            return false;
        }
        if (_stepper.GetActiveIndex() == 0)
        {
            _loading = true;
            StateHasChanged();
            await Task.Delay(1000);
            await _form.Validate();
            _loading = false;
            StateHasChanged();
            return !_form.IsValid;
        }
        else if (_stepper.GetActiveIndex() == 1)
        {
            _loading = true;
            StateHasChanged();
            await Task.Delay(1000);
            await _form2.Validate();
            _loading = false;
            StateHasChanged();
            return !_form2.IsValid;
        }
        else
        {
            return false;
        }
    }


    private async void ContextMenuItems(int options, Manager selectedManager)
    {
        switch(options)
        {
            case 0:
                //Remove
                bool? result = await DialogService.ShowMessageBox("Warning",  "Deleting can not be undone!", yesText:"Delete!", cancelText:"Cancel");
                state= result==null ? "Cancelled" : "Deleted!";
                StateHasChanged();
                //if result is yes then delete the maanager 
                if (result == true)
                {
                    await DeleteManager(selectedManager);
                }
                break;
            case 1:
                //edit    
                break;
        }
    }

    public static async Task UpdateManagerList(Manager managerObject)
    {
        //if NamedPipe property is not null or empty, update the ConnectionAddress property to be the same value as the NamedPipe field
        if (!string.IsNullOrEmpty(managerObject.NamedPipe))
        {
            managerObject.ConnectionAddress = managerObject.NamedPipe;
        }
        //if the manager is a tcp manager, update the ConnectionAddress property to be the same value as the BindAddress field
        else if (managerObject.Type == ManagerType.tcp)
        {
            if (managerObject.connectionMode == ConnectionMode.bind)
            {
                managerObject.ConnectionPort = managerObject.ListenPort;
            }
            else if (managerObject.connectionMode == ConnectionMode.reverse)
            {
                managerObject.ConnectionPort = managerObject.BindPort;
            }
        }


        managersList.Add(managerObject);
        if (managerObject != null)
        {
            ShowSuccessToast($"Manager named {managerObject.Name} has been created");
        }
    }

    public static async Task GetExistingManagerList(List<Manager> managers)
    {
        foreach (Manager manager in managers)
        {
            //if none of the managers already in the list have the same name as the one we just got from the server, add it to the list
            if (!managersList.Any(x => x.Name == manager.Name))
            {
                //if NamedPipe property is not null or empty, update the ConnectionAddress property to be the same value as the NamedPipe field
                if (!string.IsNullOrEmpty(manager.NamedPipe))
                {
                    manager.ConnectionAddress = manager.NamedPipe;
                }
                //if the manager is a tcp manager, update the ConnectionAddress property to be the same value as the BindAddress field
                else if (manager.Type == ManagerType.tcp)
                {
                    if (manager.connectionMode == ConnectionMode.bind)
                    {
                        manager.ConnectionPort = manager.ListenPort;
                    }
                    else if (manager.connectionMode == ConnectionMode.reverse)
                    {
                        manager.ConnectionPort = manager.BindPort;
                    }
                }
                managersList.Add(manager);
            }
        }
    }

    public static string displayConnectionMode(Manager manager)
    {
        if(manager.Type != ManagerType.tcp)
        {
            return "";
        }
        else
        {
            return manager.connectionMode.ToString();
        }
    }

    public async Task CreateHttpManager()
    {
        var resource = "/managers";
        ShowInfoToast("Sending Create Manager Request...");

        //if formSubmitManager.Name already exist show an error toast and return
        if (managersList.Any(x => x.Name == formSubmitManager.Name))
        {
            ShowErrorToast($"Manager named {formSubmitManager.Name} already exists");
            return;
        }
        //if a manager with the Connection address and port already exist show an error toast and return
        if (managersList.Any(x => x.ConnectionAddress == formSubmitManager.ConnectionAddress && x.ConnectionPort == formSubmitManager.ConnectionPort))
        {
            ShowErrorToast($"Manager with connection address {formSubmitManager.ConnectionAddress} and port {formSubmitManager.ConnectionPort} already exists");
            return;
        }
        //if Address is not in the format of xxx.xxx.xxx.xxx where each character is a number between 0 and 9 show an error toast and return
        //if (!Regex.IsMatch(formSubmitManager.ConnectionAddress, @"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"))
        //{
        //    ShowErrorToast($"Manager connection address {formSubmitManager.ConnectionAddress} is not in the correct format");
        //    return;
        //}
        //if port is not between 1-65535 show an error toast and return
        if (formSubmitManager.ConnectionPort < 1 || formSubmitManager.ConnectionPort > 65535)
        {
            ShowErrorToast($"Manager connection port {formSubmitManager.ConnectionPort} is not in the correct range");
            return;
        }

        var createObject = new StartHttpmanagerRequest 
        {
            Name = formSubmitManager.Name,
            ConnectionPort = (int)formSubmitManager.ConnectionPort,
            ConnectionAddress = formSubmitManager.ConnectionAddress,
            BindPort = (int)formSubmitManager.BindPort,
            BindAddress = formSubmitManager.BindAddress,
            IsSecure = false,
            C2profile = formSubmitManager.C2profile,
            managertype = ManagerType.http
        }; 
        formSubmitManager = new Manager();
        var request = new RestRequest(resource,Method.Post);
        request.AddJsonBody(createObject);
        //request.OnBeforeDeserialization = resp =>
        //{
        //    Console.WriteLine(resp.Content);
        //};
        _ = await _restClient.PostAsync<ManagerResponse>(request);
    }

    public async Task CreateHttpsManager()
    {
        ShowInfoToast("Sending Create Manager Request...");
        //if formSubmitManager.Name already exist show an error toast and return
        if (managersList.Any(x => x.Name == formSubmitManager.Name))
        {
            ShowErrorToast($"Manager named {formSubmitManager.Name} already exists");
            return;
        }
        //if a manager with the Connection address and port already exist show an error toast and return
        if (managersList.Any(x => x.BindAddress == formSubmitManager.BindAddress && x.BindPort == formSubmitManager.BindPort))
        {
            ShowErrorToast($"Manager with Bind Address {formSubmitManager.BindAddress} and port {formSubmitManager.BindPort} already exists");
            return;
        }
        //if Address is not in the format of xxx.xxx.xxx.xxx where each character is a number between 0 and 9 show an error toast and return
        if (!Regex.IsMatch(formSubmitManager.BindAddress, @"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"))
        {
            ShowErrorToast($"Manager Bind Address {formSubmitManager.BindAddress} is not in the correct format");
            return;
        }
        //if port is not between 1-65535 show an error toast and return
        if (formSubmitManager.BindPort < 1 || formSubmitManager.BindPort > 65535)
        {
            ShowErrorToast($"Manager connection port {formSubmitManager.BindPort} is not in the correct range");
            return;
        }

        var resource = "/managers";
        var createObject = new StartHttpmanagerRequest 
        {
            Name = formSubmitManager.Name,
            ConnectionPort = (int)formSubmitManager.ConnectionPort,
            ConnectionAddress = formSubmitManager.ConnectionAddress,
            BindPort = (int)formSubmitManager.BindPort,
            BindAddress = formSubmitManager.BindAddress,
            IsSecure = true,
            C2profile = formSubmitManager.C2profile
        }; 
        var request = new RestRequest(resource,Method.Post);
        request.AddJsonBody(createObject);
        _ = await _restClient.PostAsync<ManagerResponse>(request);
    }

    public async Task CreateSMBManager()
    {
        var resource = "/managers";
        ShowInfoToast("Sending Create Manager Request...");
        //if formSubmitManager.Name already exist show an error toast and return
        if (managersList.Any(x => x.Name == formSubmitManager.Name))
        {
            ShowErrorToast($"Manager named {formSubmitManager.Name} already exists");
            return;
        }
        if (managersList.Any(x => x.NamedPipe == formSubmitManager.NamedPipe))
        {
            ShowErrorToast($"Manager with pipe name {formSubmitManager.NamedPipe} already exists");
            return;
        }

        var createObject = new StartSMBmanagerRequest 
        {
            Name = formSubmitManager.Name,
            NamedPipe = formSubmitManager.NamedPipe,
            managertype = ManagerType.smb
        }; 
        if (formSubmitManager.connectionMode == ConnectionMode.bind)
        {
            createObject.Name = formSubmitManager.Name;
            createObject.NamedPipe = formSubmitManager.NamedPipe;
            createObject.managertype = ManagerType.smb;
            createObject.connectionMode = ConnectionMode.bind;
        }
        else
        {
            createObject.Name = formSubmitManager.Name;
            createObject.NamedPipe = formSubmitManager.NamedPipe;
            createObject.ConnectionAddress = formSubmitManager.ConnectionAddress;
            createObject.managertype = ManagerType.smb;
            createObject.connectionMode = ConnectionMode.reverse;
        }
        formSubmitManager = new Manager();
        var request = new RestRequest(resource,Method.Post);
        request.AddJsonBody(createObject);
        _ = await _restClient.PostAsync<ManagerResponse>(request);
    }

    public async Task CreateTCPManager()
    {
        var resource = "/managers";
        ShowInfoToast("Sending Create Manager Request...");
        //if formSubmitManager.Name already exist show an error toast and return
        if (managersList.Any(x => x.Name == formSubmitManager.Name))
        {
            ShowErrorToast($"Manager named {formSubmitManager.Name} already exists");
            return;
        }

        var createObject = new StartTCPManagerRequest();
        createObject.Name = formSubmitManager.Name;
        if(formSubmitManager.connectionMode == ConnectionMode.bind)
        {
            createObject.ListenPort = (int)formSubmitManager.ListenPort;
            createObject.IsLocalHost = (bool)formSubmitManager.IsLocalHost;
            createObject.connectionMode = ConnectionMode.bind;
            createObject.managertype = ManagerType.tcp;
        }
        else
        {
            createObject.ConnectionAddress = formSubmitManager.ConnectionAddress;
            createObject.BindPort = (int)formSubmitManager.BindPort;
            createObject.connectionMode = ConnectionMode.reverse;
            createObject.managertype = ManagerType.tcp;
        }
        formSubmitManager = new Manager();
        var request = new RestRequest(resource, Method.Post);
        request.AddJsonBody(createObject);
        _ = await _restClient.PostAsync<ManagerResponse>(request);
    }

    public async Task DeleteManager(Manager manager)
    {
        var resource = "/managers";
        var request = new RestRequest($"{resource}/{manager.Name}",Method.Delete);
        request.AddHeader("Content-Type", "application/json");
        await _restClient.DeleteAsync(request);
        managersList.Remove(manager);
    }

    private static void ShowSuccessToast(string successMessage)
    {
        _toastService.ShowSuccess(successMessage);
    }
    private static void ShowErrorToast(string errorMessage)
    {
        _toastService.ShowError(errorMessage);
    }

    private static void ShowInfoToast(string infoMessage)
    {
        _toastService.ShowInfo(infoMessage);
    }
    private static void ShowWarningToast()
    {
        _toastService.ShowWarning("This is Warning message with title");
    }

    private async Task OpenEditDialog(C2Profile profile)
    {
        try
        {
            DialogOptions options = new DialogOptions() { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Medium, FullWidth = true };
            var parameters = new DialogParameters { ["profile_ser"] = profile.Serialize_Str() };

            var dialog = DialogService.Show<EditC2Dialog>("View/Edit existing C2 Profile", parameters, options);
            var result = await dialog.Result;
            if (!result.Canceled)
            {
                C2Profile newProfile = (C2Profile)result.Data;
                //Console.WriteLine("Dialog OK");
                //Console.WriteLine($"C2 profile name is now: {newProfile.Name}");
                //Console.WriteLine($"C2 profile description is now: {newProfile.Desc}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }   
        
        
    } 

    private async Task OpenCreateDialog()
    {
                  
       
        DialogOptions options = new DialogOptions() { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Medium, FullWidth = true };

        var dialog = DialogService.Show<CreateC2Dialog>("Create New C2 Profile", options);
        //if the result is true then add the new profile to the list
        var result = await dialog.Result;

        if (!result.Canceled)
        {
            C2profiles.Add((C2Profile)result.Data);
        }

    }

    private static void PopulateC2ProfileList()
    {
        var urls = new List<string>() { "/index.html", "/" };
        var eventUrls = new List<string>() { "/e", "/events" };
        var cookies = new List<string>(){"SESSIONID" };
        var requestHeaders = new List<string>() { "Accept,Json/Application"};
        var responseHeaders = new List<string>() { "Server,Microsoft IIS" };

        List<C2Profile> c2list = new()
        {
            //new Models.C2Profile {Name= "",Desc="", UserAgent="", Urls= new List<string> { }, Cookies= new List<string> { }, RequestHeaders= new List<string> { }, ResponseHeaders= new List<string> { }  }, empty example to add more.
            new C2Profile {Name= "default",Desc="default http profile", UserAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246", 
                Urls=urls, EventUrls=eventUrls, Cookies=cookies , RequestHeaders=requestHeaders, ResponseHeaders=responseHeaders },
        };
        //compare the name of the Modles.C2Profile objects in the C2profiles list to the ones in c2list if C2Profiles does not have one with that name then update it
        foreach (var c2 in c2list)
        {
            if (!C2profiles.Any(x => x.Name.Equals(c2.Name,StringComparison.CurrentCultureIgnoreCase)))
            {
                C2profiles.Add(c2);
            }
        }
    }


    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if(firstRender)
        {
            PopulateC2ProfileList();
            RestClientOptions options = new RestClientOptions();
            options.BaseUrl = _restClient.Options.BaseUrl;
            options.RemoteCertificateValidationCallback = _restClient.Options.RemoteCertificateValidationCallback;
            string jwtToken = await LocalStorage.GetItemAsync<string>("bearerToken");
            options.Authenticator = new JwtAuthenticator(jwtToken);
            _restClient = new RestClient(options);
            bindableIpAddresses.AddRange(await HardHatHubClient._hub.GetBindableAddressesOnServer());
        }
    }

    //override the Onintalized function 
    protected override async Task OnInitializedAsync()
    {
        _toastService = (ToastService)toastService;

        if (timer is null)
        {
            timer = new Timer(new TimerCallback(_ => { InvokeAsync(StateHasChanged); }), null, 100, 100);
        }
    }

}
